package com.caijg.service.impl;

import cn.hutool.json.JSON;
import cn.hutool.json.JSONUtil;
import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversation;
import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversationParam;
import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversationResult;
import com.alibaba.dashscope.common.MultiModalMessage;
import com.alibaba.dashscope.common.Role;
import com.alibaba.dashscope.exception.NoApiKeyException;
import com.alibaba.dashscope.exception.UploadFileException;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.caijg.domain.dto.DiagnosisDTO;
import com.caijg.domain.po.TongueDiagnosis;
import com.caijg.domain.vo.Result;
import com.caijg.exception.CustomException;
import com.caijg.mapper.TongueDiagnosisMapper;
import com.caijg.service.IPromptService;
import com.caijg.service.ITongueDiagnosisService;
import com.caijg.utils.UserContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import static com.caijg.utils.Constant.*;

/**
 * <p>
 * 舌诊表 服务实现类
 * </p>
 *
 * @author caijg
 * @since 2024-12-27
 */
@Service
@Slf4j
public class TongueDiagnosisServiceImpl extends ServiceImpl<TongueDiagnosisMapper, TongueDiagnosis> implements ITongueDiagnosisService {

    @Autowired
    private IPromptService promptService;

    // 假数据
//    @Override
//    public Result diagnosis(DiagnosisDTO diagnosisDTO) throws Exception {
//        Thread.sleep(1000);
//        String s = "{" +
//                "  \"comment\": \"用户的舌头特点包括舌苔较厚、干燥粗糙且细腻，呈现白色，舌头整体偏淡红，较胖大且缺乏活力和光泽。诊断状态为湿热内蕴导致的气血不足与脾胃功能失调。饮食建议是多吃清淡、易消化的食物，如小米粥、蒸南瓜和炖莲藕，避免辛辣油腻食物。生活方式建议是保持规律作息，避免熬夜，适当增加运动以促进血液循环，同时注意保持口腔清洁和湿润。\",\n" +
//                "  \"coatingQuality\": {\n" +
//                "    \"feature\": \"厚苔、燥苔、腻苔\",\n" +
//                "    \"diagnosis\": \"脾胃湿热或痰湿内蕴\"\n" +
//                "  },\n" +
//                "  \"coatingColor\": {\n" +
//                "    \"feature\": \"白苔\",\n" +
//                "    \"diagnosis\": \"寒湿或脾胃虚寒\"\n" +
//                "  },\n" +
//                "  \"tongueVitality\": {\n" +
//                "    \"feature\": \"枯舌\",\n" +
//                "    \"diagnosis\": \"气血不足或脾胃功能失调\"\n" +
//                "  },\n" +
//                "  \"tongueColor\": {\n" +
//                "    \"feature\": \"淡红舌\",\n" +
//                "    \"diagnosis\": \"气血不足或虚寒\"\n" +
//                "  },\n" +
//                "  \"tongueShape\": {\n" +
//                "    \"feature\": \"胖大舌\",\n" +
//                "    \"diagnosis\": \"脾虚或水湿停滞\"\n" +
//                "  }\n" +
//                "}";
//
//        return Result.success(JSONUtil.parse(s));
//
//    }

    /**
     * 舌苔诊断
     * @param diagnosisDTO 舌苔图片
     */
    @Override
    @Transactional
    public Result diagnosis(DiagnosisDTO diagnosisDTO) throws Exception {
        // 1.将舌苔图片发给视觉大模型，获取舌苔特征描述
        String imageUrl = diagnosisDTO.getUrl();
        // 2.拿到视觉大模型的舌苔特征描述
        String visuallyModelResult = getVisuallyModelResult(imageUrl);

        // 3.防止大模型回复的不是纯JSON，做一个容错处理
        int begin = visuallyModelResult.indexOf("{");
        int end = visuallyModelResult.lastIndexOf("}");
        // 如果完全就没有JSON格式，则抛出异常
        if (begin == -1 || end == -1) {
            throw new CustomException("内部错误，请重试！", 500);
        }
        visuallyModelResult = visuallyModelResult.substring(begin, end + 1);

        // 4.解析诊断结果为JSON格式
        JSON jsonResult = JSONUtil.parse(visuallyModelResult);

        // 5.将诊断结果保存到数据库
        TongueDiagnosis tongueDiagnosis = new TongueDiagnosis();
        tongueDiagnosis.setUserId(diagnosisDTO.getUserId());
        tongueDiagnosis.setImageUrl(imageUrl);
        tongueDiagnosis.setCoatingQuality(jsonResult.getByPath("coatingQuality", String.class));
        tongueDiagnosis.setCoatingColor(jsonResult.getByPath("coatingColor", String.class));
        tongueDiagnosis.setTongueVitality(jsonResult.getByPath("tongueVitality", String.class));
        tongueDiagnosis.setTongueColor(jsonResult.getByPath("tongueColor", String.class));
        tongueDiagnosis.setTongueShape(jsonResult.getByPath("tongueShape", String.class));
        tongueDiagnosis.setCreateTime(LocalDateTime.now());
        this.save(tongueDiagnosis);

        // 6.给返回结果加一个ID
        jsonResult.putByPath("id", tongueDiagnosis.getId());

        // 7.返回舌苔描述
        return Result.success(jsonResult);
    }

    /**
     * 调用视觉大模型，获取舌苔特征
     * @param imageUrl 舌苔图片的URL
     * @return 舌苔的特征
     */
    private String getVisuallyModelResult(String imageUrl) throws NoApiKeyException, UploadFileException {
        // 1.创建多模态对话对象
        MultiModalConversation conv = new MultiModalConversation();
        // 2.设置提示词
        MultiModalMessage userMessage = MultiModalMessage.builder().role(Role.USER.getValue())
                .content(Arrays.asList(
                        Collections.singletonMap("image", imageUrl),
                        Collections.singletonMap("text", promptService.getPromptByName(TONGUE_PROMPT_NAME)))
                ).build();

        // 3.设置模型参数(model, apiKey, message)
        MultiModalConversationParam param = MultiModalConversationParam.builder()
                // 模型名字
                .model(VLM_NAME)
                // 用户发送的内容
                .message(userMessage)
                // 设置apikey
                .apiKey(API_KEY)
                .build();
        // 4.调用模型，获取结果
        MultiModalConversationResult result = conv.call(param);
        // 5.返回结果
        return (String) result
                .getOutput().getChoices().get(0)
                .getMessage().getContent().get(0)
                .get("text");
    }


    /**
     * 获取历史诊断记录
     */
    @Override
    public Result history() {
        // 1.获取当前用户id
        Long userId = UserContext.getUid();

        // 2.根据用户id查询历史诊断记录
        List<TongueDiagnosis> list = this.query()
                .eq("user_id", userId)
                .orderByDesc("create_time")
                .list();

        // 3.返回历史诊断记录
        return Result.success(list);
    }

    /**
     * 删除指定id的舌诊记录
     * @param ids 舌诊记录id列表
     */
    @Override
    public Result delete(ArrayList<String> ids) {
        // 1.删除指定id的记录
        boolean ok = this.removeByIds(ids);

        // 2.返回成功
        return Result.success(ok);
    }
}